/*
 * Copyright (c) 2015. 石头哥哥
 */

package com.comom.manager.service;

import com.comom.manager.kit.security.SecurityUtil;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by 石头哥哥 on 15/7/6.
 * PROJECT_NAME: server-java-mengchong
 * PACKAGE_NAME: com.mengchong.server.service
 * COMMENT : token 管理类
 */
@Service
public class TokenManager {


    /**
     * 过期时间  30天 ， 毫秒
     */
    private static final long expriedtime = 2592000000L;

    /**
     * 多线程操作 ：1. 后台清理线程；2.某session请求 处理线程；
     * token缓存  全局缓存     该对象 需要进行同步
     */
    private static final Map<Integer, String> tokenMaps = new HashMap<Integer, String>();


    /**
     * 执行token 清理线程
     */
    private ScheduledThreadPoolExecutor poolExecutor;


    /**
     *
     */
    private TokenManager() {
        poolExecutor = new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors()
                , new PriorityThreadFactory("@+token后台清理线程+@", Thread.NORM_PRIORITY));
    }


    /**
     * 后台线程 定时执行
     * 清理token
     */
    @PostConstruct
    private void clearToken() {
        this.scheduleFactionBattle(new Runnable() {
            @SuppressWarnings("SuspiciousMethodCalls")
            @Override
            public void run() {
                synchronized (tokenMaps) {
                    Collection<String> tokens = tokenMaps.values();
                    long exiperdtime;
                    long currentTime = System.currentTimeMillis();
                    for (String token : tokens) {
                        exiperdtime = getExpriedtime(token);
                        if (currentTime >= exiperdtime) {
                            //token失效
                            tokenMaps.remove(token);// no mapping , token is null
                        }

                    }
                }
            }
        }, 10, 30);// default  is 30 second
    }

    /**
     * shut down web application
     */
    @PreDestroy
    private void destroy() {
        tokenMaps.clear();
        this.poolExecutor.shutdownNow();
        this.poolExecutor = null;
    }

    /**
     * @param uid
     * @param token
     */
    public void addToken(int uid, String token) {
        synchronized (tokenMaps) {
            tokenMaps.put(uid, token);//the old value is replaced by the specified value
        }
    }


    /**
     * 获取token
     *
     * @param uid
     */
    public String getTokenByUid(int uid) {
        synchronized (tokenMaps) {
            return tokenMaps.get(uid);// may be is null
        }
    }

    /**
     * 当前 缓存是否存在指定token
     *
     * @param token
     * @return
     */
    public boolean containToken(String token) {
        synchronized (tokenMaps) {
            return tokenMaps.containsValue(token);
        }
    }


    /**
     * 验证token有效性
     *
     * @param token
     * @return
     */
    public boolean isVaildToken(String token) {
        synchronized (tokenMaps) {
            return tokenMaps.containsValue(token)
                    && System.currentTimeMillis() < getExpriedtime(token);
        }
    }


    /**
     * 移除无效token
     *
     * @param token
     */
    @SuppressWarnings("SuspiciousMethodCalls")
    public void removeUnVaildToken(String token) {
        synchronized (tokenMaps) {
            tokenMaps.remove(token);
        }
    }

    /**
     * 产生token
     *
     * @return
     */
    public String createToken(int uid) {
        long temp = System.currentTimeMillis() + expriedtime;
        return SecurityUtil.desEncrypt(uid + "_" + temp);
    }


    /**
     * @param token
     * @return
     */
    public int getUidByToken(String token) {
        return Integer.parseInt(SecurityUtil.desDecrypt(token).split("_")[0]);
    }


    /**
     * 返回 过期时间
     *
     * @param token
     * @return
     */
    public static long getExpriedtime(String token) {
        return Long.parseLong(SecurityUtil.desDecrypt(token).split("_")[1]);
    }


    /**
     * 后台处理线程
     * 定时清理token
     *
     * @param command
     * @param initialDelay
     * @param period
     * @return
     */
    private ScheduledFuture<?> scheduleFactionBattle(Runnable command,
                                                     long initialDelay,
                                                     long period) {
        return this.poolExecutor.scheduleAtFixedRate(command, initialDelay, period, TimeUnit.SECONDS);
    }


    /**
     * thread factory
     */
    public class PriorityThreadFactory implements ThreadFactory {

        private int _prio;
        private String _name;
        private AtomicInteger _threadNumber = new AtomicInteger(1);
        private ThreadGroup _group;

        public String get_name() {
            return _name;
        }

        /**
         * @param name     线程池名
         * @param priority 线程池优先级
         */
        public PriorityThreadFactory(String name, int priority) {
            _prio = priority;
            _name = name;
            _group = new ThreadGroup(_name);
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(_group, r);
            t.setName(_name + "-" + "#-" + _threadNumber.getAndIncrement());
            t.setPriority(_prio);
            return t;
        }

        public ThreadGroup getGroup() {
            return _group;
        }
    }

}

